﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Routing;
using System.Web.Mvc;
using System.Collections.Specialized;
using LiteBlog.Components;
using System.Web.Security;
using System.IO;
using LiteBlog.Common.Components;
using LiteBlog.Common.Entities;
using LiteBlog.Components.Contracts;
using LiteBlog.IoC;
using LiteBlog.Infrastructure.Constraints;
using System.Web.Optimization;
using LiteBlog.Components.Enums;

namespace LiteBlog.Infrastructure
{
    public class StartupHelper
    {
        private static readonly string SkinName = "Skin";

        public static IStatComp Startup()
        {
            RegisterControllerFactory();
            RegisterModelBinders();
            AreaRegistration.RegisterAllAreas();
            RegisterRoutes(RouteTable.Routes);
            RegisterBundles();
            
            var settingsComp = IoCContainer.Resolve<ISettingsComp>();
            settingsComp.LoadWurflManager();
            var settings = settingsComp.Load();
            DateTimeHelper.SetTimezone(settings.Timezone);
            var configComp = IoCContainer.Resolve<IConfigComp>();
            InitMembership(configComp.DataPath, settings.Timezone);
            InitLog(settings.LogFile, settings.LogLevel);

            // store the skin in the application object (explicitly)
            HttpContext.Current.Application[SkinName] = settings.Skin;
            return IoCContainer.Resolve<IStatComp>();
        }

        private static void RegisterControllerFactory()
        {
            ControllerBuilder.Current.SetControllerFactory(typeof(CustomControllerFactory));
        }

        private static void RegisterModelBinders()
        {
            ModelBinders.Binders.Add(typeof(DraftPost), new DraftPostModelBinder());
            ModelBinders.Binders.Add(typeof(PostInfo), new PostInfoModelBinder());
        }

        private static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.IgnoreRoute("favicon.ico");

            routes.MapRoute(
                "Rss",
                "Rss",
                new { controller = "Home", action = "Rss" });

            routes.MapRoute(
               "Atom",
               "Atom",
               new { controller = "Home", action = "Atom" });

            routes.MapRoute(
               "Scheduler",
               "Scheduler/{action}",
               new { controller = "Scheduler", action = "Publish" });

            routes.MapRoute(
                "Category",
                "{id}",
                new { controller = "Category", action = "Index" },
                new { id = new CategoryConstraint() });

            routes.MapRoute(
                "Post",
                "Post/{id}",
                new { controller = "Post", action = "Index" },
                new { id = new PostConstraint() });

            // Fix for previous version of LiteBlog 
            routes.MapRoute(
               "Posts",
               "Posts/{id}",
               new { controller = "Post", action = "Index" },
               new { id = new PostConstraint() });

            // Fix for previous version of LiteBlog 
            routes.MapRoute(
               "Tag",
               "Tag/{id}",
               new { controller = "Tag", action = "Index" },
               new { id = new PostConstraint() });

            routes.MapRoute(
               "Page",
               "Page/{id}",
               new { controller = "Page", action = "Index" },
               new { id = new PostConstraint() });

            routes.MapRoute(
                "Archive",
                "{year}/{month}",
                new { controller = "Archive", action = "Index" },
                new { year = new ArchiveConstraint(), month = new ArchiveConstraint() });

            routes.MapRoute(
                "Default",
                "{controller}/{action}/{id}",
                new { controller = "Home", action = "Index", id = UrlParameter.Optional });

            routes.MapRoute(
                "Missing",
                "{*any}",
                new { controller = "Home", action = "PageNotFound" });
        }

        private static void RegisterBundles()
        {
            BundleTable.EnableOptimizations = true;

            var frameworkBundle = new ScriptBundle("~/bundles/framework");
            frameworkBundle.IncludeDirectory("~/Scripts/Framework", "*.js");
            BundleTable.Bundles.Add(frameworkBundle);

            var mainKnockoutBundle = new ScriptBundle("~/bundles/knockout/public");
            mainKnockoutBundle.IncludeDirectory("~/Scripts/ViewModels/Public", "*.js");
            BundleTable.Bundles.Add(mainKnockoutBundle);

            var adminKnockoutBundle = new ScriptBundle("~/bundles/knockout/admin");
            adminKnockoutBundle.IncludeDirectory("~/Scripts/ViewModels/Admin", "*.js");
            BundleTable.Bundles.Add(adminKnockoutBundle);

            var homeBundle = new ScriptBundle("~/bundles/home");
            homeBundle.IncludeDirectory("~/Scripts/Home", "*.js");
            BundleTable.Bundles.Add(homeBundle);

            var mainUtilitiesBundle = new ScriptBundle("~/bundles/utilities/public");
            mainUtilitiesBundle.IncludeDirectory("~/Scripts/Utilities/Public", "*.js");
            BundleTable.Bundles.Add(mainUtilitiesBundle);

            var adminUtilitiesBundle = new ScriptBundle("~/bundles/utilities/admin");
            adminUtilitiesBundle.IncludeDirectory("~/Scripts/Utilities/Admin", "*.js");
            BundleTable.Bundles.Add(adminUtilitiesBundle);

            var jqueryStyle = new StyleBundle("~/bundles/jqueryui")
                                    .Include("~/Content/start/jquery-ui-1.10.3.custom.css");
            BundleTable.Bundles.Add(jqueryStyle);

            var commonStyles = new StyleBundle("~/bundles/common")
                                    .Include("~/Content/common.css");
            BundleTable.Bundles.Add(commonStyles);

            var mainStyleGreen = new StyleBundle("~/bundles/blog.green")
                                    .Include("~/Content/common.green.css")
                                    .Include("~/Content/blog.green.css");

            var adminStyleGreen = new StyleBundle("~/bundles/admin.green")
                                    .Include("~/Content/common.green.css")
                                    .Include("~/Content/admin.green.css");

            BundleTable.Bundles.Add(mainStyleGreen);
            BundleTable.Bundles.Add(adminStyleGreen);

            var mainStyleRed = new StyleBundle("~/bundles/blog.red")
                                    .Include("~/Content/common.red.css")
                                    .Include("~/Content/blog.red.css");
            var adminStyleRed = new StyleBundle("~/bundles/admin.red")
                                    .Include("~/Content/common.red.css")
                                    .Include("~/Content/admin.red.css");

            BundleTable.Bundles.Add(mainStyleRed);
            BundleTable.Bundles.Add(adminStyleRed);

            var mainStyleBlue = new StyleBundle("~/bundles/blog.blue")
                                    .Include("~/Content/common.blue.css")
                                    .Include("~/Content/blog.blue.css");
            var adminStyleBlue = new StyleBundle("~/bundles/admin.blue")
                                    .Include("~/Content/common.blue.css")
                                    .Include("~/Content/admin.blue.css");

            BundleTable.Bundles.Add(mainStyleBlue);
            BundleTable.Bundles.Add(adminStyleBlue);

            var mainStyleGray = new StyleBundle("~/bundles/blog.gray")
                                    .Include("~/Content/common.gray.css")
                                    .Include("~/Content/blog.gray.css");
            var adminStyleGray = new StyleBundle("~/bundles/admin.gray")
                                    .Include("~/Content/common.gray.css")
                                    .Include("~/Content/admin.gray.css");

            BundleTable.Bundles.Add(mainStyleGray);
            BundleTable.Bundles.Add(adminStyleGray);
        }

        private static void InitMembership(string dataPath, string timezone)
        {
            // Initialize membership provider dynamically
            // This is a hack to initialize the provider parameters dynamically
            NameValueCollection config = new NameValueCollection();
            config["DataPath"] = dataPath;
            config["Timezone"] = timezone;
            config["AppName"] = string.Empty;
            Membership.Provider.Initialize("XmlMemProv", config);
        }

        private static void InitLog(string logFile, string logLevel)
        {
            bool exists = !string.IsNullOrEmpty(logFile);
            if (exists)
                exists = File.Exists(logFile);
            if (!exists)
            {
                var path = string.Empty;
                if (HttpContext.Current != null)
                    path = Path.Combine(HttpContext.Current.Server.MapPath("~"), LogFolder);
                if (File.Exists(path))
                    File.Create(path);
                logFile = Path.Combine(path, LogFile);
            }
            Logger.Init(logFile, logLevel);
        }

        private static readonly string LogFolder = "Logs";
        private static readonly string LogFile = "log.txt";

    }
}